<template>
<div class="program-transfer">
  <unfold>
    <!-- 左侧角色列表 -->
    <template v-slot:tree-list>
      <tree-list ref="treeList" head-name="程序传输" head-icon="iconfont icontubiao-159"
                 :list="treeList" @setAct="setAct" :show-refresh="false" :show-fold="false"></tree-list>
    </template>

    <!-- 右侧 card -->
    <template v-slot:content>
      <div class="full-height relative-position page-content" style="padding: 0">
        <!--  头部-->
        <div class="file-head row no-wrap bg-primary text-white form-inline">
          <q-btn-dropdown v-show="positionType==='machine'" label="本地发送" :disable="actFile.length===0"
                          unelevated color="white" text-color="primary" class="margin-r-10 btn-dropdown" >
            <q-list dense>
              <q-item clickable v-close-popup class="no-padding">
                <q-item-section>
<!--                  <q-item-label>内部存储</q-item-label>-->
                  <q-btn label="内部存储" flat>
                    <input ref="uploadInput" type="file" @click="testMachineNum" @change="uploadManyLocalFile($event, 'cnc')" multiple
                           class="q-uploader__input overflow-hidden absolute-full" />
                  </q-btn>
                </q-item-section>
              </q-item>
              <q-item clickable v-close-popup class="no-padding">
                <q-item-section>
<!--                  <q-item-label>外部存储</q-item-label>-->
                  <q-btn label="外部存储" flat>
                    <input ref="uploadInput" type="file" @click="testMachineNum" @change="uploadManyLocalFile($event, 'box')" multiple
                           class="q-uploader__input overflow-hidden absolute-full" />
                  </q-btn>
                </q-item-section>
              </q-item>
            </q-list>
          </q-btn-dropdown>
          <q-btn-dropdown v-show="positionType==='machine'" label="远程发送" :disable="actFile.length===0"
                          unelevated color="white" text-color="primary">
            <q-list dense>
              <q-item clickable v-close-popup @click="showCloudFileDialog($event, 'cnc')">
                <q-item-section>
                  <q-item-label>内部存储</q-item-label>
                </q-item-section>
              </q-item>
              <q-item clickable v-close-popup @click="showCloudFileDialog($event, 'box')">
                <q-item-section>
                  <q-item-label>外部存储</q-item-label>
                </q-item-section>
              </q-item>
            </q-list>
          </q-btn-dropdown>

          <q-btn v-show="positionType==='file'" label="本地发送"
                 unelevated color="white" text-color="primary" class="margin-r-10" >
            <input ref="uploadInput" type="file" @change="uploadLocalFile($event)" multiple
                   class="q-uploader__input overflow-hidden absolute-full" />
          </q-btn>
          <q-btn v-show="positionType==='file'" label="远程发送" @click="showCloudFileDialog"
                 unelevated color="white" text-color="primary" class="margin-r-10" />
          <q-btn v-show="positionType==='file'" label="保存到远程" @click="showCloudSelDir" :disable="actFile.length===0"
                 unelevated color="white" text-color="primary" class="margin-r-10" />
          <q-btn v-show="positionType==='file'" label="下载到本地" :disable="actFile.length===0"
                 unelevated color="white" text-color="primary">
            <input ref="uploadInput" @click="showLocalDirDialog"
                     multiple v-show="actFile.length>0"
                   class="q-uploader__input overflow-hidden absolute-full" />
          </q-btn>

          <q-space></q-space>

          <select-input ref="selectInput" v-if="positionType==='machine'"
                        :list="searchCondition" @search="inputSearch" @clearSearchVal="clearSearchVal" />
          <q-icon v-show="positionType!=='machine'" name="iconfont icontubiao-58" class="icon" @click="back()">
            <q-tooltip>返回上一级</q-tooltip>
          </q-icon>
          <q-icon @click="changeLookStatus" v-show="positionType==='file'" :name="positionType==='list'?'iconfont icontubiao-104':'iconfont icontubiao-57'" class="icon">
            <q-tooltip>切换显示模式</q-tooltip>
          </q-icon>
          <q-icon name="iconfont icontubiao-34" class="icon" @click="refreshFun">
            <q-tooltip>刷新</q-tooltip>
          </q-icon>
        </div>
        <!--  路径-->
        <position :position="position" :total="files.length" @goto="goto" />
        <!--  内容-->
        <div class="list-content drop-target relative-position"
             @mousedown="boxStart($event,'fileList')" ref="fileList"
        >
          <div class="full-height" v-if="lookStatus==='bigIcon'" @click.self="clearActFile()">
            <q-scroll-area :thumb-style="CommonConfig.thumbStyle" class="full-height">
              <div class="full-height list" v-if="positionType!=='file'">
                <file-item v-for="(file, fileIndex) in files" :key="fileIndex" :is-show-menu="false"
                           :file="file" :file-index="fileIndex" class="machine-file"
                           :is-active="isActDay(file)"
                           @selFiles="selFiles" @dblclickE="dblclickE"
                />
              </div>
              <div class="full-height list" v-else>
                <file-item v-for="(file, fileIndex) in files" :key="fileIndex" :ref="'fileItem'+file.id"
                           :file="file" :file-index="fileIndex"
                           :is-active="isActDay(file)"
                           @selFiles="selFiles" @dblclickE="dblclickE" @setFile="setFile"
                           @setNewNameFun="setNewNameFun" @deleteFun="deleteFun"
                           @editFile="editFile"
                />
              </div>
            </q-scroll-area>
            <q-menu touch-position context-menu v-if="positionType==='file'">
              <q-list dense style="min-width: 150px">
                <q-item clickable v-close-popup @click="newFolder">
                  <q-item-section>新建文件夹</q-item-section>
                </q-item>
                <q-item clickable v-close-popup @click="newFile">
                  <q-item-section>新建文件</q-item-section>
                </q-item>
              </q-list>
            </q-menu>
          </div>
          <div class="full-height" v-if="positionType==='file'&&lookStatus!=='bigIcon'" @click.self="clearActFile">
            <q-table class="table-file" :pagination="pagination" no-data-label="暂无数据"
                     :data="files" :columns="columns" row-key="id" hide-bottom
                     binary-state-sort @request="onRequest">
              <template v-slot:body="props">
                <file-item-tr :file="props" :is-active="isActDay(props.row)" :ref="'fileItemTr'+props.row.id"
                              @selFiles="selFiles" @dblclickE="dblclickE" @setFile="setFile"
                              @setNewNameFun="setNewNameFun" @deleteFun="deleteFun"
                              @editFile="editFile"
                />
              </template>
            </q-table>
            <q-menu touch-position context-menu>
              <q-list dense style="min-width: 150px">
                <q-item clickable v-close-popup @click="newFolder">
                  <q-item-section>新建文件夹</q-item-section>
                </q-item>
                <q-item clickable v-close-popup @click="newFile">
                  <q-item-section>新建文件</q-item-section>
                </q-item>
              </q-list>
            </q-menu>
          </div>
          <div class="box-select" ref="boxSelect"></div>
          <q-inner-loading :showing="loading">
            <q-spinner-gears size="50px" color="primary" />
          </q-inner-loading>
        </div>
<!--        底部-->
        <div class="file-bottom">
          <div class="progressResult text-primary text-underline cursor-pointer"
               @click="showProgressResult">
            传输记录：正在传输({{progressFiles.length}})； 传输成功({{successProgressFiles.length}})； 传输失败({{failProgressFiles.length}})</div>
        </div>
      </div>
    </template>
  </unfold>
  <!--  右下角正在上传的弹框-->
  <progress-dialog ref="progressDialog" :list="progressFiles" />
  <!--  文件传输记录-->
  <progress-result-dialog ref="progressResult" :doing-data="doingProgressFiles"
                          :success-data="successProgressFiles" :fail-data="failProgressFiles"
                          @delOneRecord="delOneRecord" @clearRecord="clearRecord" />
  <!--  文件内容编辑插件-->
  <code-edit ref="codeEdit" :value="editFileContent" :name="editFileName" :decode="edtiFileDecode"
             :path="editFilePath" :state="codeState" @refreshList="refreshFun" @save="saveFile"></code-edit>
  <cloud-file-dialog ref="cloudFileDialog" @submit="uploadCloudFile" />
  <cloud-sel-dir ref="cloudSelDir" @submit="uploadMachineToCloud" />
</div>
</template>

<script>
import Unfold from 'src/components/unfold'
import TreeList from 'src/components/tree-list/list'
import SelectInput from 'src/components/select-input'
import Position from './components/position'
import ProgressDialog from './components/progress-dialog'
import ProgressResultDialog from './components/progress-result-dialog'
import FileItem from './components/file-item'
import FileItemTr from './components/file-item-tr'
import CodeEdit from 'src/components/code-edit/index'
import CloudFileDialog from './components/cloud-file-dialog'
import CloudSelDir from './components/cloud-sel-dir'
import { getOffsetLeft, getOffsetTop, defaultSchemesClearer, getFiletype,
  mqttErrMessage, matchFileType } from 'src/assets/js/util'
import { loadProgressSuccessRecord, loadProgressFailRecord,
  saveProgressSuccessRecord, saveProgressFailRecord,
  clearProgressSuccessRecord, clearProgressFailRecord, loadOss, saveOss } from 'src/assets/js/storage'
import { getOrganizeNested } from 'src/boot/factory/organize'
import { getEquipmentAccount } from 'src/boot/program/G-gov'
import { getFileInfo, newCncDir, newBoxDir, cncToBox, delCncfile,
  delBoxfile, renameCncfile, renameBoxfile } from 'src/boot/program/machine'
import { filelocalToMachine, machineNewFile, fileMachineLocal, fileMachineCloud } from 'src/boot/program/program-transfer'
import { readFile, getOSSAccount, cloudFileExist } from 'src/boot/program/cloud'
import { fileExist, downloadFile } from 'src/assets/js/file-dir'
import fileMqttMixin from 'src/assets/js/file-mqtt-mixin'
import boxCodeErr from 'src/assets/json/boxCodeErr'
import boxErr from 'src/assets/json/boxErr'
import { date } from 'quasar'
import { mapGetters } from 'vuex'
let OSS = require('ali-oss')
import refreshMixin from '../../assets/js/refresh-mixin'
const Path = require('path')
import _ from 'lodash'
export default {
  name: 'program-transfer',
  mixins: [fileMqttMixin, refreshMixin],
  data () {
    return {
      lookStatus: 'bigIcon', // 查看状态, list or bigIcon
      treeList: [], // 左侧树结构数据
      treeActItem: [], // 选中的树
      searchCondition: [ // 搜索选项
        { id: 'number', name: '设备编号' },
        { id: 'technician', name: '数控系统' }
      ],
      searchBy: null,
      keyword: null,
      // 列表位置
      selPathList: [], // 选中路径的位置
      loading: false, // 是否是加载状态
      actFile: [], // 选中的文件
      clickTime: null, // 区分单击与双击
      files: [], // 右侧的数据
      positionType: 'machine', // 判断当前位置是机床、内外部存储和文件列表 machine or store or file
      // 编辑内容
      editFileContent: '', // 要编辑文件的内容
      editFileName: '', // 要编辑文件的名字
      edtiFileDecode: '', // 要编辑文件的编码
      editFilePath: '', // 要编辑文件的路径
      codeState: 'edit', // 添加编辑状态，state or add
      // 表格配置
      columns: [ // 列表的头部
        { name: 'label', align: 'left', label: '文件名', field: 'label', style: 'width: 60%' },
        { name: 'size', align: 'left', label: '大小', field: 'size' },
        { name: 'timestamp', label: '修改时间', field: 'timestamp', sortable: true }
      ],
      pagination: {
        sortBy: 'timestamp',
        descending: true,
        page: 1,
        rowsPerPage: 0,
        rowsNumber: 10
      },
      // 框选数据
      parentW: 0, // 外框的宽
      parentH: 0, // 外框的高
      parentX: 0, // 外框的横坐标
      parentY: 0, // 外框的中坐标
      statPos: 'localCloud', // 定义埋点位置
      dragItem: [], // 存储拖动的数据
      // 传输数据
      progressFiles: [], // 正在传输的文件
      doingProgressFiles: [], // 正在传输的列表
      successProgressFiles: [], // 传输成功的列表
      failProgressFiles: [], // 传输失败的列表
      progressTime: null, // 存储定时器
      programArr: [], // 传输到机器文件列表的数据暂存
      transfering: false // 是否在传输中
    }
  },
  computed: {
    position () { // 当前位置
      let path = this.selPathList.reduce((total, item) => {
        return total + '/' + item.label
      }, '')
      return path
    },
    ...mapGetters([
      'userInfo'
    ])
  },
  created () {
    this.getTree()
    this.getEquipmentAccount()
    this.successProgressFiles = this.sortRecord(loadProgressSuccessRecord(this.userInfo.tenant_id))
    this.failProgressFiles = this.sortRecord(loadProgressFailRecord(this.userInfo.tenant_id))
  },
  methods: {
    /**
     * 全局刷新数据
     * author: xueli
     */
    refreshInfo () {
      this.lookStatus = 'bigIcon'
      this.treeActItem = []
      this.$refs.treeList.clearAct()
      this.selPathList = []
      this.actFile = []
      // this.positionType = 'machine'
      this.pagination = {
        sortBy: 'timestamp',
        descending: true,
        page: 1,
        rowsPerPage: 0,
        rowsNumber: 10
      }
      this.progressFiles = [] // 正在传输的文件
      this.doingProgressFiles = [] // 正在传输的列表
      this.progressTime = null // 存储定时器
      this.programArr = [] // 传输到机器文件列表的数据暂存
      this.transfering = false // 是否在传输中
      this.clearSearchVal()
      this.getTree()
      this.successProgressFiles = this.sortRecord(loadProgressSuccessRecord(this.userInfo.tenant_id))
      this.failProgressFiles = this.sortRecord(loadProgressFailRecord(this.userInfo.tenant_id))
    },
    // 获取组织架构数据
    getTree () {
      getOrganizeNested().then(res => {
        this.treeList = res.data
        this.treeListCopy = defaultSchemesClearer.clear(res.data)
      })
    },
    // 获取设备列表
    getEquipmentAccount () {
      const params = {
        searchBy: this.searchBy || undefined,
        keyword: this.keyword || undefined,
        ifBuildBox: true,
        schemeId: this.treeActItem.length > 0 ? this.treeActItem[0].id : undefined,
        schemeLevel: this.treeActItem.length > 0 ? this.treeActItem[0].level : undefined
      }
      this.loading = true
      getEquipmentAccount(params).then(res => {
        this.files = res.data.list.map(item => {
          return {
            ...item,
            label: `${item.name}(${item.assetNumber})`,
            value: item.boxStrId,
            position: 'machine',
            type: 'machine',
            isFile: true
          }
        })
        // 设置当前坐在的位置类型
        this.positionType = 'machine'
        this.loading = false
      }).catch(() => {
        this.loading = false
      })
    },
    // 设置左侧树选中项
    setAct (item) {
      this.treeActItem = [item]
      this.selPathList = [item]
      this.getEquipmentAccount()
    },

    // 刷新
    refreshFun () {
      if (this.selPathList.length === 0) {
        this.getEquipmentAccount()
        this.lookStatus = 'bigIcon'
      } else {
        let nodeAct = this.selPathList[this.selPathList.length - 1]
        if (nodeAct.hasOwnProperty('hash')) {
          this.actFile = []
          this.getEquipmentAccount()
          this.lookStatus = 'bigIcon'
        } else if (nodeAct.type === 'machine') {
          this.actFile = []
          this.getStore(nodeAct)
          this.lookStatus = 'bigIcon'
        } else {
          this.actFile = []
          this.getFiles(nodeAct.path)
        }
      }
    },
    // 返回
    back () {
      if (this.selPathList.length === 0) return
      this.selPathList.pop()
      this.refreshFun()
    },
    /**
     * 路径点击跳转到相应位置
     * 设备列表 type machine
     * 内外部存储 type store
     * 设备文件列表 type orter && 有timestamp属性
     * */
    goto (pathIndex) {
      console.log(pathIndex)
      console.log(this.selPathList)
      this.selPathList = this.selPathList.slice(0, pathIndex)
      console.log(this.selPathList)
      this.refreshFun()
    },
    // 切换显示模式
    changeLookStatus () {
      this.lookStatus = this.lookStatus === 'list' ? 'bigIcon' : 'list'
      this.pagination.sortBy = 'timestamp'
      this.pagination.descending = true
      this.refreshFun()
    },
    // 输入框搜索
    inputSearch (searchBy, keyword) {
      this.searchBy = searchBy.id
      this.keyword = keyword
      this.getEquipmentAccount()
    },
    // 清除搜索条件
    clearSearchVal () {
      this.searchBy = null
      this.keyword = null
      this.getEquipmentAccount()
    },

    // 单击选中文件，按住shift、ctrl多选
    selFiles (e, item) {
      clearTimeout(this.clickTime)
      this.clickTime = setTimeout(() => {
        if (e.ctrlKey) {
          // 按住ctrl键
          const index = this.actFile.findIndex(file => {
            return file.id === item.id
          })
          if (index > -1) {
            this.actFile = this.actFile.filter(file => {
              return file.id !== item.id
            })
          } else {
            this.actFile.push(item)
          }
        } else if (e.shiftKey) {
          // 按住shift键
          if (this.actFile.length === 0) {
            this.actFile.push(item)
          } else {
            const maxIndex = this.getMaxIndex()
            const index = this.files.findIndex(file => {
              return file.id === item.id
            })
            let actFile = this.files.filter((file, fileIndex) => {
              const condition = (index > maxIndex && fileIndex <= index && fileIndex >= maxIndex) ||
                (index < maxIndex && fileIndex >= index && fileIndex <= maxIndex) ||
                (index === maxIndex && fileIndex === index)
              return condition
            })
            this.actFile = actFile
          }
        } else {
          // 单选
          const index = this.actFile.findIndex(file => {
            return file.id === item.id
          })
          this.actFile = index > -1 ? [] : [item]
        }
      }, 250)
    },
    // 选中一个文件
    setFile (item) {
      this.actFile = [item]
    },
    // 是否是选中状态
    isActDay (file) {
      const index = this.actFile.findIndex(item => {
        return item.id === file.id
      })
      return index > -1
    },
    // 清空选中文件列表
    clearActFile (event) {
      this.actFile = []
    },
    // 双击进入子级文件夹
    dblclickE (item) {
      clearTimeout(this.clickTime)
      if (item.type === 'machine') { // 当前是机器列表页
        this.actFile = []
        this.selPathList.push(item)
        this.getStore(item)
      } else if (item.type === 'store') {
        this.actFile = []
        this.selPathList.push(item)
        this.getFiles()
      } else if (!item.isFile) {
        this.actFile = []
        this.selPathList.push(item)
        this.getFiles(item.path)
      }
    },
    // 获取内外部存储数据
    getStore (opt) {
      if (!opt.boxStrId) {
        this.noticeMessage('该设备未绑定盒子')
        return
      }
      // let params = {
      //   boxId: opt.boxStrId,
      //   requestId: this.requestId
      // }
      this.loading = true
      this.onSubscribe(opt.boxStrId)
      let fileinfo = (type) => {
        const member = {
          about: type,
          boxId: opt.boxStrId,
          requestId: this.requestId,
          path: '/'
        }
        return member
      }
      // arams)
      getFileInfo(fileinfo('cnc'))
      getFileInfo(fileinfo('box'))
      let inside = null, external = null, tabList = []
      this.client.onMessageArrived = (message) => {
        let data = JSON.parse(message.payloadString)
        console.log(data)
        this.selPathList.push(opt)
        try {
          if (data.request_id === this.requestId) {
            if (data.code === 200) {
              // 判断是否有外部存储
              if (data.cnc) {
                inside = {
                  boxId: opt.boxStrId,
                  id: 1,
                  label: '内部存储',
                  volumeUse: data.cnc_use,
                  volume: data.cnc,
                  source: 'machine',
                  position: 'cnc',
                  level: 6,
                  path: '/',
                  type: 'store',
                  isFile: true
                }
                tabList.push(inside)
              }
              // 判断是否是内部存储
              if (data.box) {
                external = {
                  boxId: opt.boxStrId,
                  id: 2,
                  label: '外部存储',
                  volumeUse: data.box_use,
                  volume: data.box,
                  source: 'machine',
                  position: 'box',
                  level: 6,
                  path: '/',
                  type: 'store',
                  isFile: true
                }
                tabList.push(external)
              }
              this.files = _.sortBy(_.uniqBy(tabList, 'id'), 'id')
              // 设置当前坐在的位置类型
              this.positionType = 'store'
            } else {
              console.error('获取列表失败')
              this.errMessage(`获取列表失败,${boxCodeErr[data.code]}`)
            }
            this.loading = false
          }
        } catch (e) {
          console.error(e)
          this.errMessage('获取列表失败')
          this.loading = false
        }
        this.selPathList = _.uniqBy(this.selPathList, 'id')
      }
      setTimeout(() => {
        if (tabList.length === 0) {
          this.loading = false
          this.unsubscribe(opt.boxStrId)
          this.selPathList.pop()
        }
      }, 5000)
    },
    // 获取文件列表
    getFiles (path = '/') {
      let selPath = this.selPathList[this.selPathList.length - 1]
      let params = {
        about: selPath.position,
        boxId: selPath.boxId,
        requestId: this.requestId,
        path: path
      }
      this.onSubscribe(selPath.boxId)
      this.loading = true
      getFileInfo(params)
      this.client.onMessageArrived = (message) => {
        let data = JSON.parse(message.payloadString)
        try {
          if (data.request_id === this.requestId) {
            if (data.code === 200) {
              // 判断是否有外部存储
              if (data.hasOwnProperty('box')) {
                let { dirData, fileData } = this.initMachineNodeData(params, data.box, 'box')
                this.files = this.lookStatus === 'bigIcon' || (this.lookStatus === 'list' && this.pagination.sortBy && this.pagination.descending)
                  ? [].concat(dirData, fileData) : [].concat(fileData, dirData)
              }
              if (data.hasOwnProperty('cnc')) {
                let { dirData, fileData } = this.initMachineNodeData(params, data.cnc, 'cnc')
                this.files = this.lookStatus === 'bigIcon' || (this.lookStatus === 'list' && this.pagination.sortBy && this.pagination.descending)
                  ? [].concat(dirData, fileData) : [].concat(fileData, dirData)
              }

              // 设置当前所在的位置类型
              this.positionType = 'file'
            } else {
              console.log('获取列表失败')
              this.errMessage(`获取列表失败,${boxCodeErr[data.code]}`)
            }
            this.loading = false
          }
        } catch (e) {
          console.error(e)
          this.errMessage('获取列表失败')
          this.loading = false
        }
      }
    },
    // 初始化文件数据
    initMachineNodeData (node, info, source) {
      let dirData = [], fileData = []
      info.forEach((item, index) => {
        // 文件夹数据
        if (item.type === 0) {
          dirData.push({
            id: index + 1,
            boxId: node.boxId,
            label: item.name,
            size: item.size,
            isFile: false,
            icon: 'img:statics/svg/file-icon.svg',
            source: 'machine',
            position: source,
            type: 'other',
            path: node.path + item.name + '/',
            timestamp: parseInt(item.modify_time * 1000)
          })
        } else if (item.type === 1) { // 文件数据
          let type = getFiletype(item.name)
          fileData.push({
            id: index + 1,
            boxId: node.boxId,
            label: item.name,
            size: item.size,
            isFile: item.type === 1,
            icon: 'img:statics/svg/' + type + '.svg',
            source: 'machine',
            position: source,
            type,
            path: node.path + item.name,
            timestamp: parseInt(item.modify_time * 1000)
          })
        }
      })
      if (this.lookStatus === 'list' && this.pagination.sortBy) {
        let sortBy = this.pagination.sortBy
        let descending = this.pagination.descending
        const sortFn = (descending
          ? (a, b) => (a[sortBy] > b[sortBy] ? -1 : a[sortBy] < b[sortBy] ? 1 : 0)
          : (a, b) => (a[sortBy] > b[sortBy] ? 1 : a[sortBy] < b[sortBy] ? -1 : 0)
        )
        dirData = dirData.sort(sortFn)
        fileData = fileData.sort(sortFn)
      }
      return { dirData, fileData }
    },
    // 表格排序
    onRequest (props) {
      const { sortBy, descending } = props.pagination
      if (sortBy) {
        const sortFn = (descending
          ? (a, b) => (a[sortBy] > b[sortBy] ? -1 : a[sortBy] < b[sortBy] ? 1 : 0)
          : (a, b) => (a[sortBy] > b[sortBy] ? 1 : a[sortBy] < b[sortBy] ? -1 : 0)
        )
        let dirs = this.files.filter(item => !item.isFile).sort(sortFn)
        let files = this.files.filter(item => item.isFile).sort(sortFn)
        this.files = descending ? [].concat(dirs, files) : [].concat(files, dirs)
        this.pagination.sortBy = sortBy
        this.pagination.descending = descending
      }
    },

    // 文件设置相关操作
    // 重命名文件夹、文件
    setNewNameFun (item, rename) {
      let nodeAct = this.selPathList[this.selPathList.length - 1]
      this.onSubscribe(item.boxId)
      // 如果名字没有变化，就这样了
      if (item.label === rename) {
        item.edit = false
        return
      }

      let newPath = nodeAct.path + '/' + rename + (item.isFile ? '' : '/')
      let params = {
        boxId: item.boxId,
        requestId: this.requestId,
        newPath: newPath,
        oldPath: item.path
      }
      if (nodeAct.position === 'cnc') {
        renameCncfile(params)
      } else if (nodeAct.position === 'box') {
        renameBoxfile(params)
      }

      let ref = (this.lookStatus === 'bigIcon' ? 'fileItem' : 'fileItemTr') + item.id
      let self = this
      this.client.onMessageArrived = (message) => {
        let data = JSON.parse(message.payloadString)
        console.log(data)
        try {
          if (data.request_id === this.requestId && data.code === 200) {
            if (data.error !== 0) {
              if (self.$refs[ref].rename) {
                self.$refs[ref].rename = item.label
              } else {
                self.$refs[ref][0].rename = item.label
              }
              // 报错
              if (data.hasOwnProperty('error')) {
                this.errMessage(boxErr[data.error])
              } else {
                this.errMessage(boxCodeErr[data.code])
              }
            } else {
              if (self.$refs[ref].edit) {
                self.$refs[ref].edit = false
              } else {
                self.$refs[ref][0].edit = false
              }
              // 刷新数据
              self.refreshFun()
            }
          } else {
          // 报错
            if (self.$refs[ref].rename) {
              self.$refs[ref].rename = item.label
            } else {
              self.$refs[ref][0].rename = item.label
            }
            if (data.hasOwnProperty('error')) {
              this.errMessage(boxErr[data.error])
            } else {
              this.errMessage(boxCodeErr[data.code])
            }
          }
        } catch (e) {
          console.error(e)
          if (self.$refs[ref].rename) {
            self.$refs[ref].rename = item.label
          } else {
            self.$refs[ref][0].rename = item.label
          }
          // self.errMessage('重命名失败')
        }
      }
    },
    // 删除文件和文件夹
    deleteFun (item) {
      this.$q.dialog({
        title: `<p class="dialog-notice-title">
<i class="iconfont icontubiao-28" ></i> 确定要删除${item.label}吗？</p>`,
        message: '删除后无法恢复',
        html: true,
        ok: {
          unelevated: true,
          label: '确认'
        },
        cancel: {
          unelevated: true,
          outline: true,
          label: '取消'
        }
      }).onOk(() => {
        this.onSubscribe(item.boxId)
        let params = {
          boxId: item.boxId,
          requestId: this.requestId,
          path: item.path
        }
        if (item.position === 'cnc') {
          delCncfile(params)
        } else if (item.position === 'box') {
          delBoxfile(params)
        }

        this.client.onMessageArrived = (message) => {
          let data = JSON.parse(message.payloadString)
          try {
            if (data.request_id === this.requestId && data.code === 200) {
              if (data.error === 0) {
                // 刷新数据
                this.refreshFun()
              } else {
                mqttErrMessage(data.error)
              }
            }
          } catch (e) {
            console.error(e)
            this.errMessage('删除失败')
          }
        }
      })
    },
    // 编辑读取文件
    editFile (item) {
      if (!this.testFileSize(item)) return
      this.editFileName = item.label
      if (matchFileType(item.label)) {
        this.errMessage('无法编辑图片文件、word文件、视频文件、音频文件、快捷方式、压缩文件！')
        return
      }
      if (item.position === 'cnc') {
        this.putMachineInside(item)
      } else {
        this.putMachine(item, item.path)
      }
    },
    // 验证文件大小是否超过1M
    testFileSize (file) {
      if (file.size > 1024 * 1024) {
        this.errMessage('文件超过1M暂不支持查看！')
        return false
      }
      return true
    },
    // 开始发送内部存储文件到外部存储文件
    putMachineInside (send) {
      let requestId1 = 'webClient' + this.userInfo.user_id.toString() + Date.parse(new Date()).toString()
      let params1 = {
        boxId: send.boxId,
        cncPath: send.path,
        requestId: requestId1
      }
      this.onSubscribe(send.boxId)
      cncToBox(params1)
      this.client.onMessageArrived = (message) => {
        let data = JSON.parse(message.payloadString)
        console.log(data)
        try {
          // 这里是放置对其他消息进行处理
          if (requestId1 === data.request_id && data.hasOwnProperty('error')) {
            if (data.error === 0) {
              this.putMachine(send, data.file_path)
            } else {
              this.errMessage(`文件内容读取失败！${boxErr[data.error]}`)
            }
          }
        } catch (e) {
          console.error('文件内容读取失败！')
        }
      }
    },
    // 从机床传输到云端的方法
    putMachine (send, path) {
      let params = {
        boxId: send.boxId,
        fileName: send.label,
        filePath: path,
        fromBox: send.position === 'box' ? 1 : 0
      }
      let requestId
      // let cloudDownloadUrl
      fileMachineLocal(params).then(res => {
        requestId = res.data.requestId
        // cloudDownloadUrl = res.data.url
        this.onSubscribe2(res.data.requestId)
      })
      // 上传开始时间
      this.client.onMessageArrived = (message) => {
        console.log(message)
        let data = JSON.parse(message.payloadString)
        try {
          // 这里是放置对其他消息进行处理
          if (requestId === data.request_id) {
            if (data.hasOwnProperty('source') && data.source === 'send_result') {
              if (data.code === 200) {
                // 盒子上传到云端已完成，接下来是从云端获取内容
                this.getFileContent(send, data.url)
              } else {
                this.errMessage(`文件内容读取失败！${boxCodeErr[data.error]}`)
              }
            }
          }
        } catch (e) {
          console.error(e)
          this.errMessage(`文件内容读取失败！`)
        }
      }
    },
    // 通过云端接口读取云端文件内容
    getFileContent (send, sendPath) {
      readFile(sendPath).then(res => {
        this.editFileContent = res.data
        this.editFilePath = send.path
        this.codeState = 'edit'
        this.$refs.codeEdit.showDialog()
      })
    },
    // 保存文件
    saveFile (path, code) {
      if (code.length === 0) {
        this.noticeMessage('设备里文件内容不能为空！')
        return
      }
      let nodeAct = this.selPathList[this.selPathList.length - 1]
      if (nodeAct.position === 'cnc' && this.codeState === 'edit') {
        this.delEditFile(path, code)
      } else {
        this.saveFileFuc(path, code)
      }
    },
    // 编辑操作，保存时，先删掉内部存储对应的文件
    delEditFile (path, code) {
      let nodeAct = this.selPathList[this.selPathList.length - 1]
      this.onSubscribe(nodeAct.boxId)
      let params = {
        boxId: nodeAct.boxId,
        requestId: this.requestId,
        path: path
      }
      delCncfile(params)

      this.client.onMessageArrived = (message) => {
        let data = JSON.parse(message.payloadString)
        try {
          if (data.request_id === this.requestId && data.code === 200) {
            if (data.error === 0) {
              // 刷新数据
              this.saveFileFuc(path, code)
            } else {
              mqttErrMessage(data.error)
            }
          }
        } catch (e) {
          console.error(e)
          this.errMessage('保存失败')
        }
      }
    },
    // 添加文件
    saveFileFuc (path, code) {
      let nodeAct = this.selPathList[this.selPathList.length - 1]
      let params = {
        boxId: nodeAct.boxId,
        content: code,
        fileName: this.editFileName,
        storagePath: nodeAct.path,
        toCnc: nodeAct.position === 'cnc' ? 1 : 0
      }
      let requestId
      machineNewFile(params).then(res => {
        requestId = res.data.requestId
        this.onSubscribe2(res.data.requestId)
        if (nodeAct.position === 'cnc') {
          this.onSubscribe(nodeAct.boxId)
        }
        this.editFileContent = ''
        this.$refs.codeEdit.hideDialog()
      })
      this.client.onMessageArrived = (message) => {
        let data = JSON.parse(message.payloadString)
        console.log(message)
        try {
          if (requestId === data.request_id) {
            // 判断外部存储新建文件完成
            if (data.source === 'send_result') {
              if (data.code === 200) {
                let successMessage = `<p class="dialog-notice-title"><i class="iconfont icontubiao-53"></i> ${this.codeState === 'edit' ? '修改' : '添加'}文件${this.editFileName}成功</p>`
                this.$q.dialog({
                  title: successMessage,
                  html: true,
                  ok: {
                    unelevated: true,
                    label: '确认'
                  }
                })
                this.refreshFun()
              } else if (data.code !== 200) {
                this.errMessage(`${this.codeState === 'edit' ? '修改' : '添加'}文件${this.editFileName}失败！${boxCodeErr[data.code]}`)
              }
            } else if (data.hasOwnProperty('error')) {
              // 判断内部存储新建文件完成
              if (data.error === 0) {
                let successMessage = `<p class="dialog-notice-title"><i class="iconfont icontubiao-53"></i> ${this.codeState === 'edit' ? '修改' : '添加'}文件${this.editFileName}成功</p>`
                this.$q.dialog({
                  title: successMessage,
                  html: true,
                  ok: {
                    unelevated: true,
                    label: '确认'
                  }
                })
                this.refreshFun()
              } else {
                this.errMessage(`${this.codeState === 'edit' ? '修改' : '添加'}文件${this.editFileName}失败！${boxErr[data.error]}`)
              }
            }
          }
        } catch (e) {
          console.error(e)
        }
      }
    },

    // 新建操作
    // 新建文件夹
    newFolder () {
      let nodeAct = this.selPathList[this.selPathList.length - 1]
      this.$q.dialog({
        class: 'prompt-dialog',
        title: '文件夹名称',
        prompt: {
          model: '',
          type: 'text'
        },
        ok: {
          unelevated: true,
          label: '确认'
        },
        cancel: {
          unelevated: true,
          outline: true,
          label: '取消'
        },
        persistent: true
      }).onOk(data => {
        if (data.length === 0) {
          this.$q.dialog({
            title: `<p class="dialog-notice-title">
<i class="iconfont icontubiao-28" ></i> 提示</p>`,
            message: '名称不能为空',
            html: true,
            ok: {
              unelevated: true,
              label: '确认'
            }
          })
          return false
        }
        if (data.length > 20) {
          this.$q.dialog({
            title: `<p class="dialog-notice-title">
<i class="iconfont icontubiao-28" ></i> 提示</p>`,
            message: '名称长度必须小于20',
            html: true,
            ok: {
              unelevated: true,
              label: '确认'
            }
          })
          return false
        }
        let findIndex = this.files.findIndex(item => !item.isFile && item.label === data)
        if (findIndex > -1) {
          this.$q.dialog({
            title: `<p class="dialog-notice-title">
<i class="iconfont icontubiao-28" ></i> 提示</p>`,
            message: `文件夹${data}已存在`,
            html: true,
            ok: {
              unelevated: true,
              label: '确认'
            }
          })
          return false
        }
        this.onSubscribe(nodeAct.boxId)
        let params = {
          boxId: nodeAct.boxId,
          requestId: this.requestId,
          path: nodeAct.path + data
        }
        if (nodeAct.position === 'cnc') {
          newCncDir(params)
        } else if (nodeAct.position === 'box') {
          newBoxDir(params)
        }

        this.client.onMessageArrived = (message) => {
          let data = JSON.parse(message.payloadString)
          try {
            if (data.request_id === this.requestId && data.code === 200) {
              if (data.error === 0) {
                // 刷新数据
                this.refreshFun()
              } else {
                mqttErrMessage(data.error)
              }
            }
          } catch (e) {
            console.error(e)
            this.errMessage('新建文件夹失败')
          }
        }
      })
    },
    // 新建文件
    newFile () {
      let nodeAct = this.selPathList[this.selPathList.length - 1]
      this.$q.dialog({
        class: 'prompt-dialog',
        title: '文件名称',
        prompt: {
          model: '',
          type: 'text'
        },
        ok: {
          unelevated: true,
          label: '确认'
        },
        cancel: {
          unelevated: true,
          outline: true,
          label: '取消'
        },
        persistent: true
      }).onOk(data => {
        if (data.length === 0) {
          this.$q.dialog({
            title: `<p class="dialog-notice-title">
<i class="iconfont icontubiao-28" ></i> 提示</p>`,
            message: '名称不能为空',
            html: true,
            ok: {
              unelevated: true,
              label: '确认'
            }
          })
          return false
        }
        if (data.length > 20) {
          this.$q.dialog({
            title: `<p class="dialog-notice-title">
<i class="iconfont icontubiao-28" ></i> 提示</p>`,
            message: '名称长度必须小于20',
            html: true,
            ok: {
              unelevated: true,
              label: '确认'
            }
          })
          return false
        }
        let findIndex = this.files.findIndex(item => item.isFile && item.label === data)
        if (findIndex > -1) {
          this.$q.dialog({
            title: `<p class="dialog-notice-title">
<i class="iconfont icontubiao-28" ></i> 提示</p>`,
            message: `文件${data}已存在`,
            html: true,
            ok: {
              unelevated: true,
              label: '确认'
            }
          })
          return false
        }
        this.editFilePath = nodeAct.path + data
        this.editFileName = data
        this.editFileContent = ''
        this.edtiFileDecode = ''
        this.codeState = 'add'
        this.$refs.codeEdit.showDialog()
      })
    },

    // 文件传输
    // 多设备文件传输
    // 显示本地选择文件件弹框
    testMachineNum (event) {
      if (this.actFile.length === 0) {
        this.noticeMessage('请先选择要传输到设备位置')
        if (event.preventDefault) {
          event.preventDefault()
        } else {
          event.returnValue = false
        }
      }
    },
    /**
     * 本地上传
     * event input事件
     * position 传输位置，cnc or box
     */
    uploadManyLocalFile (event, position) {
      const files = event.target.files
      // 传输前的验证
      if (!this.testUploadLocalFile(files)) {
        return
      }
      this.actFile.forEach(machine => {
        for (let i = 0; i < files.length; i++) {
          let file = files[i]
          // 添加到传输队列
          this.addMachineProgramArr(machine, file, 'local', position)
        }
      })
      this.startProgram()
      event.target.value = ''
    },
    /**
     * 设备页面添加到传输列表
     */
    addMachineProgramArr (machine, sendFile, sendSource, machinePosition) {
      this.programArr.push({
        machine,
        sendFile,
        sendSource,
        machinePosition,
        sendStatus: 'many' // 发送时处于设备列表页
      })
      let startTime = new Date()
      let progress = {
        name: sendSource === 'local' ? sendFile.name : sendFile.label, // 文件名字
        progress: 0, // 传输进度
        state: 'upload', // 上传状态 upload:正在上传，download:正在下载，success：传输成功，fail：传输失败
        partSize: 16, // 每次上传的大小
        fileSize: 0, // 文件总大小
        acceptPath: '/', // 接收方地址
        startTime, // 开始时间
        sender: sendSource, // 发送方
        acceptor: `machine(${machinePosition === 'cnc' ? '内部存储' : '外部存储'})`, // 接收方
        endTime: this.dateToString(new Date()),
        useTime: this.getUseTime(startTime, new Date()),
        boxId: machine.boxStrId
      }
      this.addProgressFiles(progress)
    },

    // 单设备文件传输
    // 本地上传到机床
    uploadLocalFile (event) {
      const files = event.target.files
      // 传输前的验证
      if (!this.testUploadLocalFile(files)) {
        return
      }
      let nodeAct = this.selPathList[this.selPathList.length - 1]
      for (let i = 0; i < files.length; i++) {
        let file = files[i]
        if (this.machineFileExist(nodeAct.path, file.name)) {
          if (nodeAct.position === 'cnc') {
            this.$q.dialog({
              title: `<p class="dialog-notice-title"><i class="iconfont icontubiao-28" ></i> 提示</p>`,
              message: '文件' + file.name + '已存在，内部存储不允许覆盖文件',
              html: true,
              ok: {
                unelevated: true,
                label: '确认'
              },
              persistent: true
            })
          } else {
            this.$q.dialog({
              title: `<p class="dialog-notice-title"><i class="iconfont icontubiao-28" ></i> 提示</p>`,
              message: `文件${file.name}已存在，是否覆盖文件?`,
              html: true,
              ok: {
                unelevated: true,
                label: '确认'
              },
              cancel: {
                unelevated: true,
                outline: true,
                label: '取消'
              },
              persistent: true
            }).onOk(data => {
              // 添加到传输队列
              this.addProgramArr(file, nodeAct.path, 'local', `machine(${nodeAct.position === 'cnc' ? '内部存储' : '外部存储'})`)
              // 开始下载
              this.startProgram()
            })
          }
        } else {
          // 添加到传输队列
          this.addProgramArr(file, nodeAct.path, 'local', `machine(${nodeAct.position === 'cnc' ? '内部存储' : '外部存储'})`)
        }
      }
      // 开始下载
      this.startProgram()
      event.target.value = ''
    },
    // 发送本地文件到机器的方法
    putLocalToMachine (program) {
      let self = this
      let nodeAct = program.nodeAct
      // 获取当前发送信息
      let requestId
      let startTime = new Date()
      let formdata = new FormData()
      let position, boxId, acceptPath
      // 上一个进度
      let lastProgress = null, filesize = program.sendFile.size
      if (program.sendStatus === 'single') {
        position = nodeAct.position
        boxId = nodeAct.boxId
        acceptPath = position === 'cnc' ? nodeAct.path : nodeAct.path + program.sendFile.name
      } else {
        position = program.machinePosition
        boxId = program.machine.boxStrId
        acceptPath = position === 'cnc' ? '/' : '/' + program.sendFile.name
      }
      let progress = {
        name: program.sendFile.name, // 文件名字
        progress: 1, // 传输进度
        state: 'success', // 上传状态 upload:正在上传，download:正在下载，success：传输成功，fail：传输失败
        partSize: 16, // 每次上传的大小
        fileSize: filesize, // 文件总大小
        acceptPath, // 接收方地址
        startTime, // 开始时间
        sender: program.sendSource, // 发送方
        acceptor: `machine(${position === 'cnc' ? '内部存储' : '外部存储'})`, // 接收方
        endTime: self.dateToString(new Date()),
        useTime: self.getUseTime(startTime, new Date())
      }

      formdata.append('boxId', boxId)
      formdata.append('file', program.sendFile)
      formdata.append('storagePath', acceptPath)
      formdata.append('toCnc', position === 'cnc' ? 1 : 0)
      formdata.append('fileName', program.sendFile.name)

      if (position === 'cnc') {
        this.onSubscribe(boxId)
      }
      filelocalToMachine(formdata).then(res => {
        if (res.data.hasOwnProperty('requestId')) {
          requestId = res.data.requestId
          this.onSubscribe1(res.data.requestId)
          this.onSubscribe2(res.data.requestId)
        } else {
          // 传输失败，开始传下一个
          this.transfering = false
          this.startProgram()
          // 报告进度
          progress.progress = 1
          progress.state = 'fail'
          progress.reason = res.data.hasOwnProperty('errorMessage') ? res.data.errorMessage : '系统出错'
          progress.endTime = self.dateToString(new Date())
          progress.useTime = self.getUseTime(startTime, new Date())
          self.addProgressFiles(progress)
        }
      })
      // 发送到多台的数据标识
      if (program.sendStatus === 'many') {
        progress.boxId = boxId
      }
      this.client.onMessageArrived = (message) => {
        let data = JSON.parse(message.payloadString)
        console.log(data)
        try {
          if (requestId === data.request_id) {
            // 内部存储逻辑，当data.err===0才是传输成功
            if (position === 'cnc') {
              // 判断是内部存储发来的消息
              if (message.destinationName === `${this.CommonConfig.mqttConfig.MQTT_TOPIC.machineFileInfo.subscribeTopic}${boxId}`) {
                if (data.hasOwnProperty('error') && data.error === 0) {
                  // 报告进度
                  progress.progress = 1
                  progress.state = 'success'
                  progress.endTime = self.dateToString(new Date())
                  progress.useTime = self.getUseTime(startTime, new Date())
                  this.addProgressFiles(progress)
                  // 传输成功，开始传下一个
                  this.transfering = false
                  this.startProgram()
                  // 上传成功，刷新列表
                  if (program.sendStatus === 'single') {
                    this.refreshFun()
                  }
                } else {
                  // 传输失败，开始传下一个
                  this.transfering = false
                  this.startProgram()
                  // 报告进度
                  progress.progress = 1
                  progress.state = 'fail'
                  progress.reason = data.hasOwnProperty('error') ? boxErr[data.error] : boxCodeErr[data.code]
                  progress.endTime = self.dateToString(new Date())
                  progress.useTime = self.getUseTime(startTime, new Date())
                  self.addProgressFiles(progress)
                }
              } else if (data.hasOwnProperty('source') && data.source === 'send_result') {
                if (data.code !== 200) {
                  // 传输失败，开始传下一个
                  this.transfering = false
                  this.startProgram()
                  // 报告进度
                  progress.progress = 1
                  progress.state = 'fail'
                  progress.reason = boxCodeErr[data.code]
                  progress.endTime = self.dateToString(new Date())
                  progress.useTime = self.getUseTime(startTime, new Date())
                  self.addProgressFiles(progress)
                }
              } else if (lastProgress === null || lastProgress.progress < data.rate) {
                // 这里是防止顺序错乱
                progress.progress = data.rate
                progress.state = 'upload'
                progress.endTime = self.dateToString(new Date())
                progress.useTime = self.getUseTime(startTime, new Date())
                lastProgress = progress
                self.addProgressFiles(progress)
              }
            } else {
              // 外部存储逻辑，当data.code===200才是传输成功
              if (data.hasOwnProperty('source') && data.source === 'send_result') {
                if (data.code === 200) {
                  // 报告进度
                  progress.progress = 1
                  progress.state = 'success'
                  progress.endTime = self.dateToString(new Date())
                  progress.useTime = self.getUseTime(startTime, new Date())
                  self.addProgressFiles(progress)
                  // 上传成功，刷新列表
                  // 传输成功，开始传下一个
                  self.transfering = false
                  self.startProgram()
                  // 上传成功，刷新列表
                  if (program.sendStatus === 'single') {
                    this.refreshFun()
                  }
                } else {
                  // 传输失败，开始传下一个
                  this.transfering = false
                  this.startProgram()
                  // 报告进度
                  progress.progress = 1
                  progress.state = 'fail'
                  progress.reason = boxCodeErr[data.code]
                  progress.endTime = self.dateToString(new Date())
                  progress.useTime = self.getUseTime(startTime, new Date())
                  self.addProgressFiles(progress)
                  self.addProgressFiles(progress)
                }
              } else if (lastProgress === null || lastProgress.progress < data.rate) {
                // 这里是防止顺序错乱
                progress.progress = data.rate
                progress.state = 'upload'
                progress.endTime = self.dateToString(new Date())
                progress.useTime = self.getUseTime(startTime, new Date())
                lastProgress = progress
                self.addProgressFiles(progress)
              }
            }
          }
        } catch (e) {
          console.error(e)
          // 传输失败，开始传下一个
          this.transfering = false
          this.startProgram()
          // 报告进度
          progress.progress = 1
          progress.state = 'fail'
          progress.reason = '程序出错'
          progress.endTime = self.dateToString(new Date())
          progress.useTime = self.getUseTime(startTime, new Date())
          self.addProgressFiles(progress)
        }
      }
    },
    // 上传验证
    testUploadLocalFile (files) {
      if (files.length > 50) { // 超过50个不能上传
        this.errMessage('一次上传不能超过50个文件')
        return false
      }
      if (files.length === 0) {
        this.errMessage('当前没有选择文件')
        return false
      }
      if (!this.testFilesSize(files)) {
        return false
      }
      return true
    },
    // 验证要发送的文件大小是否符合规则
    testFilesSize (files) {
      console.log(files)
      for (let i = 0; i < files.length; i++) {
        if (files[i].size > 50 * 1024 * 1024) {
          this.errMessage(`文件${files[i].label ? files[i].label : files[i].name}大小超过50M，请重新选择要上传文件`)
          return false
        }
      }
      return true
    },
    // 判断文件是否存在
    machineFileExist (path, label) {
      let exist = false
      for (let i = 0; i < this.files.length; i++) {
        if (this.files[i].isFile && this.files[i].label === label) {
          exist = true
          break
        }
      }
      return exist
    },

    // 显示本地选择文件夹弹框
    showLocalDirDialog (event) {
      let files = this.actFile.filter(item => {
        return item.isFile
      })
      if (files.length === 0) {
        this.noticeMessage('请先选择要下载到本地的文件')
        if (event.preventDefault) {
          event.preventDefault()
        } else {
          event.returnValue = false
        }
        return
      }
      let dialog
      dialog.showOpenDialog({
        // 选择操作，此处是打开文件夹
        properties: [
          'openDirectory'
        ]
      }).then(result => {
        if (!result.canceled) {
          this.downloadLocalFiles(result.filePaths[0])
        }
        console.log(result.filePaths)
      }).catch(err => {
        console.log(err)
      })
    },
    // 机床下载到本地
    async downloadLocalFiles (event) {
      // 当前选中的文件
      let files = this.actFile.filter(item => {
        return item.isFile
      })
      if (files.length === 0) {
        this.noticeMessage('请先选择要下载的文件')
      }
      let oss = await this.getOss()
      this.clientCloud = new OSS({
        region: oss.region,
        accessKeyId: oss.accessKeyId,
        accessKeySecret: oss.accessKeySecret,
        stsToken: oss.securityToken,
        bucket: oss.bucket
      })
      let localPath = event
      localPath = Path.normalize(localPath) + Path.sep
      console.log(localPath)
      for (let i = 0; i < files.length; i++) {
        let file = files[i]
        let savePath = Path.normalize(localPath + file.label)
        if (fileExist(savePath)) {
          this.$q.dialog({
            title: `<p class="dialog-notice-title">
<i class="iconfont icontubiao-28" ></i> 提示</p>`,
            message: '文件' + file.label + '已存在，是否覆盖文件',
            html: true,
            ok: {
              unelevated: true,
              label: '确认'
            },
            cancel: {
              unelevated: true,
              outline: true,
              label: '取消'
            },
            persistent: true
          }).onOk(data => {
            // 添加到传输队列
            this.addProgramArr(file, savePath, `machine(${file.position === 'cnc' ? '内部存储' : '外部存储'})`, 'local')
            // 开始下载
            this.startProgram()
          })
        } else {
          // 添加到传输队列
          this.addProgramArr(file, savePath, `machine(${file.position === 'cnc' ? '内部存储' : '外部存储'})`, 'local')
        }
      }
      // 开始下载
      this.startProgram()
    },
    // 下载机器文件到本地的方法
    // 开始发送内部存储文件到外部存储文件
    putMachineInsideToLocal (program, source) {
      let send = program.sendFile
      let acceptPath = program.acceptSource === 'cloud' ? program.saveAcceptPath : program.acceptPath
      let requestId1 = 'webClient' + this.userInfo.user_id.toString() + Date.parse(new Date()).toString()
      let self = this
      let params1 = {
        boxId: send.boxId,
        cncPath: send.path,
        requestId: requestId1
      }
      this.onSubscribe(send.boxId)
      cncToBox(params1)
      let startTime = new Date()
      this.client.onMessageArrived = (message) => {
        let data = JSON.parse(message.payloadString)
        console.log(data)
        try {
          // 这里是放置对其他消息进行处理
          if (requestId1 === data.request_id &&
            message.destinationName === `${this.CommonConfig.mqttConfig.MQTT_TOPIC.machineFileInfo.subscribeTopic}${send.boxId}`) {
            if (data.hasOwnProperty('error') && data.error === 0) {
              let sendPath = data.file_path
              this.putMachineToLocal(program, source, sendPath)
            } else {
              if (data.hasOwnProperty('error')) {
                this.errMessage(boxErr[data.error])
              }
              let progress = {
                name: send.label, // 文件名字
                progress: 1, // 传输进度
                state: 'fail', // 上传状态 upload:正在上传，download:正在下载，success：传输成功，fail：传输失败
                partSize: 16, // 每次上传的大小
                fileSize: send.size, // 文件总大小
                acceptPath, // 接收方地址
                startTime, // 开始时间
                sender: `machine(${send.position === 'cnc' ? '内部存储' : '外部存储'})`, // 发送方
                acceptor: source === 'machineToLocal' ? 'local' : 'cloud', // 接收方
                reason: boxErr[data.code], // 传输失败原因
                endTime: self.dateToString(new Date()),
                useTime: '00:00:00'
              }
              // 传输失败，开始传下一个
              this.transfering = false
              this.startProgram()
              self.addProgressFiles(progress)
            }
          }
        } catch (e) {
          console.error(e)
          let progress = {
            name: send.label, // 文件名字
            progress: 1, // 传输进度
            state: 'fail', // 上传状态 upload:正在上传，download:正在下载，success：传输成功，fail：传输失败
            partSize: 16, // 每次上传的大小
            fileSize: send.size, // 文件总大小
            acceptPath, // 接收方地址
            startTime, // 开始时间
            sender: `machine(${send.position === 'cnc' ? '内部存储' : '外部存储'})`, // 发送方
            acceptor: source === 'machineToLocal' ? 'local' : 'cloud', // 接收方
            reason: boxErr[data.code], // 传输失败原因
            endTime: self.dateToString(new Date()),
            useTime: '00:00:00'
          }
          // 传输失败，开始传下一个
          this.transfering = false
          this.startProgram()
          self.addProgressFiles(progress)
        }
      }
    },
    // 从机床下载到本地的方法
    putMachineToLocal (program, source, sendPath = '') {
      let self = this
      let send = program.sendFile
      let acceptPath = program.acceptSource === 'cloud' ? program.saveAcceptPath : program.acceptPath
      let params = {
        boxId: send.boxId,
        fileName: send.label,
        filePath: sendPath.length > 0 ? sendPath : send.path,
        fromBox: send.position === 'box' ? 1 : 0
      }
      if (source === 'machineToCloud') {
        params.cloudPath = program.acceptPath
      }
      let requestId
      fileMachineLocal(params).then(res => {
        requestId = res.data.requestId
        this.onSubscribe1(res.data.requestId)
        this.onSubscribe2(res.data.requestId)
      })
      // 上一个进度
      let lastProgress = null
      // 上传开始时间
      let startTime = new Date()
      let fileSize = send.size
      this.client.onMessageArrived = (message) => {
        let data = JSON.parse(message.payloadString)
        console.log(data)
        try {
          // 这里是放置对其他消息进行处理
          if (requestId === data.request_id) {
            if (data.hasOwnProperty('source') && data.source === 'send_result') {
              if (data.code === 200) {
                let progress = {
                  name: send.label, // 文件名字
                  progress: source === 'machineToLocal' ? 0.9 : 1, // 传输进度
                  state: source === 'machineToLocal' ? 'upload' : 'success', // 上传状态 upload:正在上传，download:正在下载，success：传输成功，fail：传输失败
                  partSize: 16, // 每次上传的大小
                  fileSize, // 文件总大小
                  acceptPath, // 接收方地址
                  startTime, // 开始时间
                  sender: `machine(${send.position === 'cnc' ? '内部存储' : '外部存储'})`, // 发送方
                  acceptor: source === 'machineToLocal' ? 'local' : 'cloud', // 接收方
                  endTime: self.dateToString(new Date()),
                  useTime: self.getUseTime(startTime, new Date())
                }
                console.log(progress)
                this.addProgressFiles(progress)
                // console.log(data.url)
                // 判断是传输到本地还是传输到云端，传输到本地还要进行文件下载操作
                if (source === 'machineToLocal') {
                  // 盒子上传到云端已完成，接下来是从云端下载到本地的过程
                  this.putCloudToLocal(send, acceptPath, data.url)
                } else {
                  this.transfering = false
                  this.startProgram()
                }
              } else {
                let progress = {
                  name: send.label, // 文件名字
                  progress: 1, // 传输进度
                  state: 'fail', // 上传状态 upload:正在上传，download:正在下载，success：传输成功，fail：传输失败
                  partSize: 16, // 每次上传的大小
                  fileSize, // 文件总大小
                  acceptPath, // 接收方地址
                  startTime, // 开始时间
                  sender: `machine(${send.position === 'cnc' ? '内部存储' : '外部存储'})`, // 发送方
                  acceptor: source === 'machineToLocal' ? 'local' : 'cloud', // 接收方
                  reason: boxCodeErr[data.code],
                  endTime: self.dateToString(new Date()),
                  useTime: self.getUseTime(startTime, new Date())
                }
                this.addProgressFiles(progress)
                // 传输失败，开始传下一个
                this.transfering = false
                this.startProgram()
              }
            } else if (lastProgress === null || lastProgress.progress < data.rate) { // 记录传输进度
              // 这里是方式顺序错乱
              let progress = {
                name: send.label, // 文件名字
                progress: data.rate, // 传输进度
                state: 'upload', // 上传状态 upload:正在上传，download:正在下载，success：传输成功，fail：传输失败
                partSize: 16, // 每次上传的大小
                fileSize, // 文件总大小
                acceptPath, // 接收方地址
                startTime, // 开始时间
                sender: `machine(${send.position === 'cnc' ? '内部存储' : '外部存储'})`, // 发送方
                acceptor: source === 'machineToLocal' ? 'local' : 'cloud', // 接收方
                endTime: self.dateToString(new Date()),
                useTime: self.getUseTime(startTime, new Date())
              }
              lastProgress = progress
              this.addProgressFiles(progress)
            }
          }
        } catch (e) {
          console.error(e)
          let progress = {
            name: send.label, // 文件名字
            progress: 1, // 传输进度
            state: 'fail', // 上传状态 upload:正在上传，download:正在下载，success：传输成功，fail：传输失败
            partSize: 16, // 每次上传的大小
            fileSize, // 文件总大小
            acceptPath, // 接收方地址
            startTime, // 开始时间
            sender: `machine(${send.position === 'cnc' ? '内部存储' : '外部存储'})`, // 发送方
            acceptor: source === 'machineToLocal' ? 'local' : 'cloud', // 接收方
            reason: '程序出错',
            endTime: this.dateToString(new Date()),
            useTime: this.getUseTime(startTime, new Date())
          }
          this.addProgressFiles(progress)
          // 传输失败，开始传下一个
          this.transfering = false
          this.startProgram()
        }
      }
    },
    /**
     * 发送云端文件到本地的方法并监听进度
     * @param sendFile 要发送的云端文件文件
     * @param localFilePath 要发送到本地的位置
     * @returns {Promise<void>}
     */
    async putCloudToLocal (sendFile, localFilePath, cloudDownloadPath) {
      let startTime = new Date()
      let progress = {
        name: sendFile.label, // 文件名字
        progress: 0.66, // 传输进度
        state: 'download', // 上传状态 upload:正在上传，download:正在下载，success：传输成功，fail：传输失败
        partSize: sendFile.size, // 每次上传的大小
        fileSize: sendFile.size, // 文件总大小
        acceptPath: localFilePath, // 接收方地址
        startTime, // 开始时间
        sender: `machine(${sendFile.position === 'cnc' ? '内部存储' : '外部存储'})`, // 发送方
        acceptor: 'local', // 接收方
        endTime: date.formatDate(new Date(), 'MM-DD HH:mm:ss'),
        useTime: this.getUseTime(startTime, new Date())
      }
      let url = await this.clientCloud.signatureUrl(cloudDownloadPath)
      // 流式下载文件
      await downloadFile(url, localFilePath, (info) => {
        let fileRate = info.progress === 1 ? 1 : info.progress / 3 + 0.66
        progress.size = info.size
        progress.progress = fileRate
        progress.receiveBytes = info.receiveBytes
        progress.state = info.state
        progress.endTime = date.formatDate(new Date(), 'MM-DD HH:mm:ss')
        progress.useTime = this.getUseTime(startTime, new Date())
        this.addProgressFiles(progress)
        if (info.state === 'success') {
          // 传输失败，开始传下一个
          this.transfering = false
          this.startProgram()
        }
      })
    },

    // 云端到机床
    showCloudFileDialog (event, machinePosition) {
      let position = machinePosition
      if (!machinePosition) {
        let nodeAct = this.selPathList[this.selPathList.length - 1]
        position = nodeAct.position
      }

      this.$refs.cloudFileDialog.showDialog(position)
    },
    /**
     * 云端上传到机床
     * @param cloudFiles 选中的云端文件列表
     * @param machinePosition 发送给内部存储还是外部存储，多设备发送用
     */
    uploadCloudFile (cloudFiles, machinePosition) {
      // 传输前的验证
      if (!this.testUploadLocalFile(cloudFiles)) {
        return
      }
      // 当前所在位置，machineList：机床列表，fileList：文件列表
      let nodeAct = this.selPathList[this.selPathList.length - 1]

      if (this.positionType === 'machine') {
        this.actFile.forEach(machine => {
          cloudFiles.forEach(file => {
            // 添加到传输队列
            this.addMachineProgramArr(machine, file, 'cloud', machinePosition)
          })
        })
      } else if (this.positionType === 'file') {
        cloudFiles.forEach(file => {
          if (this.machineFileExist(nodeAct.path, file.label)) {
            if (nodeAct.position === 'cnc') {
              this.$q.dialog({
                title: `<p class="dialog-notice-title"><i class="iconfont icontubiao-28" ></i> 提示</p>`,
                message: '文件' + file.name + '已存在，内部存储不允许覆盖文件',
                html: true,
                ok: {
                  unelevated: true,
                  label: '确认'
                },
                persistent: true
              })
            } else {
              this.$q.dialog({
                title: `<p class="dialog-notice-title"><i class="iconfont icontubiao-28" ></i> 提示</p>`,
                message: `文件${file.name}已存在，是否覆盖文件?`,
                html: true,
                ok: {
                  unelevated: true,
                  label: '确认'
                },
                cancel: {
                  unelevated: true,
                  outline: true,
                  label: '取消'
                },
                persistent: true
              }).onOk(data => {
                // 添加到传输队列
                this.addProgramArr(file, nodeAct.path, 'cloud', `machine(${nodeAct.position === 'cnc' ? '内部存储' : '外部存储'})`)
                // 开始下载
                this.startProgram()
              })
            }
          } else {
            // 添加到传输队列
            this.addProgramArr(file, nodeAct.path, 'cloud', `machine(${nodeAct.position === 'cnc' ? '内部存储' : '外部存储'})`)
          }
        })
      }
      // 开始下载
      this.startProgram()
    },
    // 从云端上传到机床的方法
    putCloudToMachine (program) {
      let self = this
      let nodeAct = program.nodeAct
      let position, boxId, storagePath

      if (program.sendStatus === 'single') {
        position = nodeAct.position
        boxId = nodeAct.boxId
        storagePath = nodeAct.path
      } else {
        position = program.machinePosition
        boxId = program.machine.boxStrId
        storagePath = '/'
      }
      // 上一个进度
      let lastProgress = null
      let acceptPath = storagePath + program.sendFile.label // 接收路径
      let fileSize = program.sendFile.size // 文件大小
      let startTime = new Date()
      let progress = {
        name: program.sendFile.label, // 文件名字
        progress: 0, // 传输进度
        state: 'upload', // 上传状态 upload:正在上传，download:正在下载，success：传输成功，fail：传输失败
        partSize: 16, // 每次上传的大小
        fileSize, // 文件总大小
        acceptPath, // 接收方地址
        startTime, // 开始时间
        sender: 'cloud', // 发送方
        acceptor: `machine(${position === 'cnc' ? '内部存储' : '外部存储'})`, // 接收方
        endTime: self.dateToString(new Date()),
        useTime: self.getUseTime(startTime, new Date())
      }

      let params = {
        boxId: boxId,
        cloudPath: program.sendFile.path,
        storagePath,
        toCnc: position === 'box' ? 0 : 1
      }
      let requestId
      if (position === 'cnc') {
        this.onSubscribe(boxId)
      }
      fileMachineCloud(params).then(res => {
        if (res.data.hasOwnProperty('requestId')) {
          requestId = res.data.requestId
          this.onSubscribe1(res.data.requestId)
          this.onSubscribe2(res.data.requestId)
        } else {
          // 传输失败，开始传下一个
          this.transfering = false
          this.startProgram()
          progress.progress = 1
          progress.state = 'fail'
          progress.reason = res.data.hasOwnProperty('errorMessage') ? res.data.errorMessage : '系统出错'
          progress.endTime = self.dateToString(new Date())
          progress.useTime = self.getUseTime(startTime, new Date())
          this.addProgressFiles(progress)
        }
      })

      // 发送到多台的数据标识
      if (program.sendStatus === 'many') {
        progress.boxId = program.machine.boxStrId
      }
      this.client.onMessageArrived = (message) => {
        let data = JSON.parse(message.payloadString)
        console.log(data)
        try {
          if (requestId === data.request_id) {
            // 判断是发给内部存储还是外部存储
            // 发给内部存储
            if (position === 'cnc') {
              // 判断result消息
              if (message.destinationName === `${this.CommonConfig.mqttConfig.MQTT_TOPIC.machineFileInfo.subscribeTopic}${boxId}`) {
                // if (data.hasOwnProperty('error')) {
                if (data.error === 0) { // 内部存储发送成功
                  progress.progress = 1
                  progress.state = 'success'
                  progress.endTime = self.dateToString(new Date())
                  progress.useTime = self.getUseTime(startTime, new Date())
                  this.addProgressFiles(progress)
                  // 上传成功，刷新列表
                  this.refreshFun()
                  // 传输成功，开始传下一个
                  this.transfering = false
                  this.startProgram()
                } else { // 内部存储发送失败
                  // 传输失败，开始传下一个
                  this.transfering = false
                  this.startProgram()
                  progress.progress = 1
                  progress.state = 'fail'
                  progress.reason = data.hasOwnProperty('error') ? boxErr[data.error] : boxCodeErr[data.code]
                  progress.endTime = self.dateToString(new Date())
                  progress.useTime = self.getUseTime(startTime, new Date())
                  this.addProgressFiles(progress)
                }
              } else if (data.source === 'send_result' && data.code !== 200) {
                // 传输失败，开始传下一个
                this.transfering = false
                this.startProgram()
                progress.progress = 1
                progress.state = 'fail'
                progress.reason = boxCodeErr[data.code]
                progress.endTime = self.dateToString(new Date())
                progress.useTime = self.getUseTime(startTime, new Date())
                this.addProgressFiles(progress)
              } else if (data.source === 'send_info' && (lastProgress === null || lastProgress.progress < data.rate)) {
                // 监听sendInfo发来的进度
                progress.progress = data.rate / 4 * 3
                progress.state = 'upload'
                progress.endTime = self.dateToString(new Date())
                progress.useTime = self.getUseTime(startTime, new Date())
                this.addProgressFiles(progress)
              }
            } else { // 发给外部存储
              if (data.source === 'send_result' && data.hasOwnProperty('code')) {
                if (data.code === 200) {
                  // 传输成功，开始传下一个
                  this.transfering = false
                  this.startProgram()
                  progress.progress = 1
                  progress.state = 'success'
                  progress.endTime = self.dateToString(new Date())
                  progress.useTime = self.getUseTime(startTime, new Date())
                  this.addProgressFiles(progress)
                  // 发送成功，刷新数据
                  this.refreshFun()
                } else {
                  // 传输失败，开始传下一个
                  this.transfering = false
                  this.startProgram()
                  progress.progress = 1
                  progress.state = 'fail'
                  progress.reason = boxCodeErr[data.code]
                  progress.endTime = self.dateToString(new Date())
                  progress.useTime = self.getUseTime(startTime, new Date())
                  this.addProgressFiles(progress)
                }
              } else if (data.source === 'send_info' && (lastProgress === null || lastProgress.progress < data.rate)) { // 监听sendInfo发来的进度
                progress.progress = data.rate
                progress.state = 'upload'
                progress.endTime = self.dateToString(new Date())
                progress.useTime = self.getUseTime(startTime, new Date())
                this.addProgressFiles(progress)
              }
            }
          }
        } catch (e) {
          console.error(e)
          // 传输失败，开始传下一个
          this.transfering = false
          this.startProgram()
          progress.progress = data.rate
          progress.state = 'fail'
          progress.reason = '程序出错'
          progress.endTime = self.dateToString(new Date())
          progress.useTime = self.getUseTime(startTime, new Date())
          this.addProgressFiles(progress)
        }
      }
    },

    // 机床到云端
    showCloudSelDir () {
      let files = this.actFile.filter(item => {
        return item.isFile
      })
      if (files.length === 0) {
        this.noticeMessage('请先选择要保存到远程的文件')
        return
      }
      this.$refs.cloudSelDir.showDialog()
    },
    /**
     * 通过弹框获取的云端要传输的所在位置
     * @param cloudDir 云端文件夹目录
     */
    uploadMachineToCloud (cloudDir) {
      let files = this.actFile.filter(item => {
        return item.isFile
      })
      if (!this.testUploadLocalFile(files)) return
      files.forEach(item => {
        // 判断文件是否存在
        let savePath = cloudDir.path + item.label
        cloudFileExist(savePath).then(res => {
          if (res.data) {
            this.$q.dialog({
              title: `<p class="dialog-notice-title">
<i class="iconfont icontubiao-28" ></i> 提示</p>`,
              message: '文件' + item.label + '已存在，是否覆盖文件',
              html: true,
              ok: {
                unelevated: true,
                label: '确认'
              },
              cancel: {
                unelevated: true,
                outline: true,
                label: '取消'
              },
              persistent: true
            }).onOk(data => {
              this.addProgramArr(item, cloudDir.path, `machine(${item.position === 'cnc' ? '内部存储' : '外部存储'})`, 'cloud', cloudDir.name)
              this.startProgram()
            })
          } else {
            this.addProgramArr(item, cloudDir.path, `machine(${item.position === 'cnc' ? '内部存储' : '外部存储'})`, 'cloud', cloudDir.name)
            this.startProgram()
          }
        })
      })
    },

    // 添加到传输列表。发送时，处于文件列表页
    addProgramArr (sendFile, acceptPath, sendSource, acceptSource, saveAcceptPath) {
      let nodeAct = this.selPathList[this.selPathList.length - 1]
      this.programArr.push({
        sendFile,
        acceptPath,
        sendSource,
        acceptSource,
        nodeAct,
        saveAcceptPath,
        sendStatus: 'single' // 发送时，处于文件列表页
      })
      let startTime = new Date()
      let progress = {
        name: sendSource === 'local' ? sendFile.name : sendFile.label, // 文件名字
        progress: 0, // 传输进度
        state: 'upload', // 上传状态 upload:正在上传，download:正在下载，success：传输成功，fail：传输失败
        partSize: 16, // 每次上传的大小
        fileSize: 0, // 文件总大小
        acceptPath: acceptSource === 'cloud' ? acceptPath : saveAcceptPath, // 接收方地址
        startTime, // 开始时间
        sender: sendSource, // 发送方
        acceptor: acceptSource, // 接收方
        endTime: this.dateToString(new Date()),
        useTime: this.getUseTime(startTime, new Date())
      }
      this.addProgressFiles(progress)
    },
    // 传输一个文件
    startProgram () {
      // 如果此时已在传输中，这次请求就打回
      if (this.transfering) {
        return
      }
      if (this.programArr.length > 0) {
        let program = this.programArr.shift()
        this.transfering = true
        setTimeout(() => {
          // 在文件页面发送
          if (program.sendStatus === 'single') {
            if (program.sendSource === 'local' && program.acceptSource.indexOf('machine') > -1) { // 本地到机床
              this.putLocalToMachine(program)
            } else if (program.acceptSource === 'local' && program.sendSource.indexOf('machine') > -1) { // 机床到本地
              if (program.sendFile.position === 'cnc') {
                this.putMachineInsideToLocal(program, 'machineToLocal')
              } else {
                this.putMachineToLocal(program, 'machineToLocal')
              }
            } else if (program.sendSource === 'cloud' && program.acceptSource.indexOf('machine') > -1) { // 云端到机床
              this.putCloudToMachine(program)
            } else if (program.acceptSource === 'cloud' && program.sendSource.indexOf('machine') > -1) { // 机床到云端
              if (program.sendFile.position === 'cnc') {
                this.putMachineInsideToLocal(program, 'machineToCloud')
              } else {
                this.putMachineToLocal(program, 'machineToCloud')
              }
            }
          } else { // 在设备页面发送
            if (program.sendSource === 'local') {
              this.putLocalToMachine(program)
            } else if (program.sendSource === 'cloud') {
              this.putCloudToMachine(program)
            }
          }
        }, 300)
      }
    },
    // 根据开始时间和结束时间，获取累计用时时间，返回hh:mm:ss
    getUseTime (startTime, endTime) {
      let useTime = (endTime.getTime() - startTime.getTime()) / 1000
      let seconds = parseInt(useTime % 60)
      seconds = seconds < 10 ? '0' + seconds : seconds
      let minutes = parseInt(useTime / 60 % 60)
      minutes = minutes < 10 ? '0' + minutes : minutes
      let hours = parseInt(useTime / 3600 % 60)
      hours = hours < 10 ? '0' + hours : hours
      return `${hours}:${minutes}:${seconds}`
    },
    // 根据Date格式的日期,返回 mm-dd hh:mm
    dateToString (date) {
      let months = date.getMonth() + 1
      months = months < 10 ? '0' + months : months
      let dates = date.getDate()
      dates = dates < 10 ? '0' + dates : dates
      let hours = date.getHours()
      hours = hours < 10 ? '0' + hours : hours
      let minutes = date.getMinutes()
      minutes = minutes < 10 ? '0' + minutes : minutes
      return `${months}-${dates} ${hours}:${minutes}`
    },

    // 获取oss账号
    async getOss () {
      let oss = loadOss()
      if (!oss && !oss.expiration) {
        await this.refreshOSSAccout().then(newOss => {
          oss = newOss
        })
      } else {
        let overTime = new Date(oss.expiration)
        let now = new Date()
        if (now.getTime() < overTime.getTime() - 60) {
          return oss
        } else {
          await this.refreshOSSAccout().then(newOss => {
            oss = newOss
          })
        }
      }
      return oss
    },
    // 更新oss账号
    refreshOSSAccout () {
      return getOSSAccount().then(res => {
        let oss = res.data
        saveOss(oss)
        return Promise.resolve(oss)
      })
    },

    // 传输过程中相关
    // 添加上传中和上传完成的文件
    addProgressFiles (file) {
      // 添加传输目录
      const index = this.progressFiles.findIndex(item => {
        if (file.hasOwnProperty('boxId')) {
          return item.name === file.name && item.acceptor === file.acceptor && item.boxId === file.boxId
        } else {
          return item.name === file.name && item.acceptor === file.acceptor
        }
      })

      // 开始传输
      if (index === -1) {
        this.$refs.progressDialog.showDialog()
        this.progressFiles.unshift(file)
      } else {
        this.progressFiles[index].progress = file.progress
        this.progressFiles[index].useTime = file.useTime
        this.progressFiles[index].state = file.state
        this.progressFiles[index].fileSize = file.fileSize
      }
      // 传输失败
      if (file.state === 'fail') {
        this.failProgressFiles.unshift(file)
        saveProgressFailRecord(this.userInfo.tenant_id, this.failProgressFiles)
      } else if (file.state === 'success') { // 传输成功
        this.successProgressFiles.unshift(file)
        saveProgressSuccessRecord(this.userInfo.tenant_id, this.successProgressFiles)
      }
      this.doingProgressFiles = this.progressFiles.filter(item => {
        return item.state !== 'fail' && item.state !== 'success'
      })
      this.isOverProgress()
    },
    // 判断所有文件是否上传完成，完成择1.5s后消失
    isOverProgress () {
      if (this.doingProgressFiles.length === 0) {
        this.progressTime = setTimeout(() => {
          this.$refs.progressDialog.hideDialog()
          this.progressFiles = []
        }, 1500)
      } else {
        clearTimeout(this.progressTime)
      }
    },
    // 传输记录相关
    // 显示传输记录弹框
    showProgressResult () {
      this.$refs.progressResult.showDialog()
    },
    // 删除一条传输记录
    delOneRecord (state, file) {
      if (state === 'success') {
        this.successProgressFiles = this.successProgressFiles.filter(item => {
          return !(item.name === file.name && item.startTime === file.startTime)
        })
        saveProgressSuccessRecord(this.userInfo.tenant_id, this.successProgressFiles)
      }
      if (state === 'fail') {
        this.failProgressFiles = this.failProgressFiles.filter(item => {
          return item.name !== file.name && item.startTime !== file.startTime
        })
        saveProgressFailRecord(this.userInfo.tenant_id, this.failProgressFiles)
      }
    },
    // 清空传输记录
    clearRecord (state) {
      if (state === 'success') {
        this.successProgressFiles = []
        clearProgressSuccessRecord(this.userInfo.tenant_id, this.successProgressFiles)
      }
      if (state === 'fail') {
        this.failProgressFiles = []
        clearProgressFailRecord(this.userInfo.tenant_id, this.failProgressFiles)
      }
    },
    // 传输记录按照时间排序
    sortRecord (record) {
      let newRecord = record.sort((a, b) => {
        if (a.endTime < b.endTime) {
          return 1
        } else if (a.endTime > b.endTime) {
          return -1
        } else return 0
      })
      newRecord = newRecord.map(item => {
        return {
          ...item,
          acceptPath: item.acceptPath.replace('//', '/')
        }
      })
      return newRecord
    },

    // 框选
    // 鼠标按下事件
    boxStart (event, parentDom) {
      if (event.target.tagName === 'IMG' ||
        event.target.tagName === 'SPAN' ||
        event.target.className.indexOf('txt-ellipsis') > -1) {
        return true
      }
      // 判断鼠标是否是左键按下
      if (event.buttons !== 1 || event.which !== 1) return
      let parentNode = this.$refs[parentDom]
      this.parentX = getOffsetLeft(parentNode)
      this.parentY = getOffsetTop(parentNode)
      this.parentW = parentNode.clientWidth
      this.parentH = parentNode.clientHeight
      let self = this
      clearTimeout(this.mouseTime)
      let startTime = new Date()

      this.mouseOn = true
      this.startX = event.clientX - this.parentX
      this.startY = event.clientY - this.parentY
      let boxSelect = this.$refs.boxSelect
      boxSelect.style.display = 'block'
      boxSelect.style.left = this.startX + 'px'
      boxSelect.style.top = this.startY + 'px'
      boxSelect.style.zIndex = -1
      boxSelect.style.width = 0
      boxSelect.style.height = 0
      document.onmousemove = function (event) {
        self.boxMove(event, parentDom)
      }
      this.$refs[parentDom].onmouseup = function (event) {
        // self.$refs[parentDom].onmousemove = null
        document.onmousemove = null
        clearTimeout(this.mouseTime)
        let endTime = new Date()
        if (endTime.getTime() - startTime.getTime() < 200) {
          self.isClickEvent = true
        }
        self.boxStop(event)
      }
    },
    // 鼠标移动事件
    boxMove (event, parentDom) {
      // 如果框选没有开启。退出
      if (!this.mouseOn) return

      let clientX = event.clientX
      let clientY = event.clientY
      let _x = clientX - this.parentX
      let _y = clientY - this.parentY
      let boxSelect = this.$refs.boxSelect

      boxSelect.style.left = Math.min(_x, this.startX) + 'px'
      boxSelect.style.top = Math.min(_y, this.startY) + 'px'
      boxSelect.style.width = Math.abs(_x - this.startX) + 'px'
      boxSelect.style.height = Math.abs(_y - this.startY) + 'px'
      boxSelect.style.zIndex = 100
      this.findNodes(event)
      // 当框选超出范围时，结束框选操作,取消move和mouseup监听
      if (clientX < this.parentX || clientX > this.parentX + this.parentW || clientY < this.parentY || clientY > this.parentY + this.parentH) {
        document.onmousemove = null
        this.$refs[parentDom].onmouseup = null
        clearTimeout(this.mouseTime)

        this.boxStop(event)
      }
    },
    // 鼠标松开事件
    boxStop (event) {
      this.mouseOn = false
      this.findNodes(event)
      let boxSelect = this.$refs.boxSelect
      boxSelect.style.display = 'none'
      boxSelect.style.width = 0
      boxSelect.style.height = 0
    },
    // 获取框选下的元素
    findNodes (event) {
      let dayNodes = document.getElementsByClassName('file-item')
      let boxSelect = this.$refs.boxSelect
      let selectedEls = []
      // 获取框的参数
      let l = boxSelect.offsetLeft
      let t = boxSelect.offsetTop
      let w = boxSelect.offsetWidth
      let h = boxSelect.offsetHeight

      for (let i = 0; i < dayNodes.length; i++) {
        let dayNode = dayNodes[i]
        let sl = dayNode.offsetWidth + dayNode.offsetLeft
        let st = dayNode.offsetHeight + dayNode.offsetTop
        if (sl > l && st > t && dayNode.offsetLeft < l + w && dayNode.offsetTop < t + h) {
          selectedEls.push(this.files[i])
        }
      }
      if (event.ctrlKey || event.shiftKey) {
        this.actFile = this.actFile.concat(selectedEls)
      } else {
        this.actFile = selectedEls
      }
    },

    // 提示
    // 成功提示
    successMessage (message) {
      this.$q.dialog({
        title: `<p class="dialog-notice-title">
<i class="iconfont icontubiao-53"></i> ${message}</p>`,
        html: true,
        ok: {
          unelevated: true,
          label: '确认'
        }
      })
    },
    // 失败提示
    errMessage (message) {
      this.$q.dialog({
        title: `<p class="dialog-notice-title">
<i class="iconfont icontubiao-52" ></i> 提示</p>`,
        message: message,
        html: true,
        ok: {
          unelevated: true,
          label: '确认'
        }
      })
    },
    // 注意提示
    noticeMessage (message) {
      this.$q.dialog({
        title: `<p class="dialog-notice-title">
<i class="iconfont icontubiao-28" ></i> 提示</p>`,
        message: message,
        html: true,
        ok: {
          unelevated: true,
          label: '确认'
        }
      })
    }
  },
  components: {
    TreeList,
    Unfold,
    SelectInput,
    Position,
    ProgressDialog,
    ProgressResultDialog,
    FileItem,
    FileItemTr,
    CodeEdit,
    CloudFileDialog,
    CloudSelDir
  }
}
</script>

<style scoped lang="stylus">
.program-transfer{
  .file-head{
    padding 0 20px
    height 40px
    line-height 40px
    font-size 14px
    align-items center
    flex 40px 0
    .icon{
      margin-left 10px
      font-size 18px
    }
    /deep/ .q-btn-group > .q-btn-item:not(:last-child) {
      min-width 78px
      padding 0px
    }
    /deep/ .q-btn-group > .q-btn-item + .q-btn-item {
      min-width 14px
      width 18px
      padding 0
    }
    .btn-dropdown{
      min-width 100px
    }
  }
  .list-content{
    height calc(100% - 121px)
  }
  .list{
    padding 10px
    display flex
    flex-wrap wrap
  }
  .table-file {
    height 100%
  }
  .machine-file{
    width 156px
    height 140px
    /deep/ dt{
      margin-bottom 16px
      .q-icon{
        font-size 72px
      }
    }
  }
  .file-bottom{
    text-align right
    padding 0 20px
    height 39px
    line-height 39px
    border-top 1px solid #d3d3d3
    .text-underline{
      text-decoration underline
    }
  }
  // 框选样式
  .box-select{
    position absolute
    margin 0
    padding 0
    top 0
    left 0
    width 10px
    height 10px
    border 1px dashed $primary
    background-color $primary
    z-index 1000
    opacity 0.6
    display none
  }
}
</style>
